#include "StdAfx.h"

enum class OperationType {
	Invalid = 0,
	Padding,
	Address,
	Unescape,
	Neg,
	JsByteArray
};

int32_t wmain(int32_t nArgc, const wchar_t* pArgv[]) {
	vector<wstring> Args(&pArgv[0], &pArgv[0 + nArgc]);
	shared_ptr<Interface> Intf = make_shared<Interface>(Args);

	if (nArgc < 5) {
		Intf->Log("* Usage: %ws --op <padding|address|unescape|neg|js-dword-array> --ds <data string> --df <data file path> -c <output count>\r\n", pArgv[0]);
	}
	else {
		OperationType Op = OperationType::Invalid;
		wstring DataStr;
		wstring DataFilePath;
		int32_t nCount = 0;

		for (vector<wstring>::const_iterator i = Args.begin(); i != Args.end(); ++i) {
			wstring Arg = *i;
			transform(Arg.begin(), Arg.end(), Arg.begin(), ::tolower);
			
			if (Arg == L"--op") {
				if (*(i + 1) == L"padding") {
					Op = OperationType::Padding;
				}
				else if (*(i + 1) == L"address") {
					Op = OperationType::Address;
				}
				else if (*(i + 1) == L"unescape") {
					Op = OperationType::Unescape;
				}
				else if (*(i + 1) == L"neg") {
					Op = OperationType::Neg;
				}
				else if (*(i + 1) == L"js-dword-array") {
					Op = OperationType::JsByteArray;
				}
			}
			else if (Arg == L"--ds") {
				DataStr = wstring((*(i + 1)));
			}
			else if (Arg == L"--df") {
				DataFilePath = wstring((*(i + 1)));
			}
			else if (Arg == L"-c") {
				nCount = _wtoi((*(i + 1)).c_str());
			}
		}

		unique_ptr<uint8_t[]> Data;
		uint32_t dwDataSize = 0;
		uint8_t* pAddress = nullptr;

		if (!DataFilePath.empty()) {
			try {
				FileBase DataFile(DataFilePath);
				dwDataSize = DataFile.GetSize();
				Data = make_unique<uint8_t[]>(DataFile.GetSize());
				memcpy(Data.get(), DataFile.GetData(), DataFile.GetSize());
				
			}
			catch (int32_t nError) {
				//
			}
		}
		else if (!DataStr.empty()) {
			if (wcslen(DataStr.c_str()) == 10) {
				pAddress = (uint8_t*)wcstoul(DataStr.c_str(), NULL, 0);
				dwDataSize = 4;
				Data = make_unique<uint8_t[]>(dwDataSize);
				memcpy(Data.get(), &pAddress, dwDataSize);
			}
			else {
				Intf->Log("... invalid data string (expected a 10 byte 32-bit hex address)\r\n");
			}
		}

		if (!Data && DataStr.empty()) {
			Intf->Log("... fatal error: no input data specified\r\n");
		}

		if (Op == OperationType::Padding) {
			for (int32_t nX = 0; nX < nCount; nX++) {
				Intf->Log("%ws", DataStr.c_str());
			}
		}
		else if (Op == OperationType::JsByteArray) {
			Intf->Log("var DwordArray = [ ");

			for (int32_t nX = 0; nX < dwDataSize; nX += 4) {
				Intf->Log("0x%08x, ", *(uint32_t *)&Data[nX]);
		}

			Intf->Log("];");
		}
		else if (Op == OperationType::Neg) {
#ifdef _WIN64
			pAddress = (uint8_t*)wcstoull(DataStr.c_str(), NULL, 0);
			Intf->Log("0x%p", -(uint64_t)pAddress);
#else
			pAddress = (uint8_t*)wcstoul(DataStr.c_str(), NULL, 0);
			dwDataSize = 4;
			uint8_t* pNegValue = (uint8_t *)(-(int32_t)pAddress);
			Intf->Log("0x%08p", pNegValue);
			Data = make_unique<uint8_t[]>(dwDataSize);
			Op = OperationType::Unescape;
			memcpy(Data.get(), &pNegValue, dwDataSize);
			Intf->Log("\r\n");
#endif
		}
		
		if (Op == OperationType::Unescape) {
			if (dwDataSize % 2 != 0) {
				
				unique_ptr<uint8_t[]> Temp = make_unique<uint8_t[]>(dwDataSize);
				memcpy(Temp.get(), Data.get(), dwDataSize);
				dwDataSize++;
				Data = make_unique<uint8_t[]>(dwDataSize);
				ZeroMemory(Data.get(), dwDataSize);
				memcpy(Data.get(), Temp.get(), dwDataSize);
			}

			Intf->Log("unescape(\"");
			
			for (int32_t nX = 0; nX < dwDataSize; nX += 2) {
				Intf->Log("%%u%02x%02x", Data[nX + 1], Data[nX]);
			}

			Intf->Log("\");");
		}
		else if (Op == OperationType::Address) {
#ifdef _WIN64
			pAddress = (uint8_t*)wcstoull(DataStr.c_str(), NULL, 0);
#else
			pAddress = (uint8_t*)wcstoul(DataStr.c_str(), NULL, 0);
#endif
			//Intf->Log("0x%p\r\n", pAddress);
			uint8_t* pBuf = (uint8_t*)&pAddress;
			for (int32_t nX = 0; nX < sizeof(pAddress); nX++) {
				//char c = pAddress[nX];
				Intf->Log("\\x%02x", pBuf[nX]);
				//pAddress++;
			}
		}
	}

	return 0;
}